<script lang="jsx">
/**
 *  exceljs + handsontable
 */
 import Excel from 'exceljs'
// import { useState } from 'react';

import { HotTable } from '@handsontable/react';
import { registerAllModules } from 'handsontable/registry';
import 'handsontable/dist/handsontable.full.min.css';
import { textRenderer, registerRenderer } from 'handsontable/renderers';

import {XMLParser} from 'fast-xml-parser'
import Color from 'color';

// 注册模块
registerAllModules();

// 根据主题和明暗度获取颜色
const getThemeColor = (themeJson, themeId, tint) => {
    let color = '';
    const themeColorScheme = themeJson['a:theme']['a:themeElements']['a:clrScheme'];
    switch (themeId) {
        case 0:
            color = themeColorScheme['a:lt1']['a:sysClr']['_lastClr'];
            break;
        case 1:
            color = themeColorScheme['a:dk1']['a:sysClr']['_lastClr'];
            break;
        case 2:
            color = themeColorScheme['a:lt2']['a:srgbClr']['_val'];
            break;
        case 3:
            color = themeColorScheme['a:dk2']['a:srgbClr']['_val'];
            break;
        default:
            color = themeColorScheme[`a:accent${themeId-3}`]['a:srgbClr']['_val'];
            break;
    }
    // 根据tint修改颜色深浅
    color = '#' + color;
    const colorObj = Color(color);
    if(tint){
        if(tint>0){// 淡色
            color = colorObj.lighten(tint).hex();
        }else{ // 深色
            color = colorObj.darken(Math.abs(tint)).hex();
        }
    }
    return color;
}
// 获取颜色
const getColor = (obj, themeJson) => {
    if('argb' in obj){ // 标准色 
        // rgba格式去掉前两位: FFFF0000 -> FF0000
        return '#' + obj.argb.substring(2);
    }else if('theme' in obj){ // 主题颜色
        if('tint' in obj){
            return getThemeColor(themeJson, obj.theme, obj.tint);
        }else{
            return getThemeColor(themeJson, obj.theme, null);
        }                
    }
}
// 设置边框
const setBorder = (style) =>{
    let borderStyle = 'solid';
    let borderWidth = '1px';
    switch (style) {
        case 'thin':
            borderWidth = 'thin';
            break;
        case 'dotted':
            borderStyle = 'dotted';
            break;
        case 'dashDot':
            borderStyle = 'dashed';
            break;
        case 'hair':
            borderStyle = 'solid';
            break;
        case 'dashDotDot':
            borderStyle = 'dashed';
            break;
        case 'slantDashDot':
            borderStyle = 'dashed';
            break;
        case 'medium':
            borderWidth = '2px';
            break;
        case 'mediumDashed':
            borderStyle = 'dashed';
            borderWidth = '2px';
            break;
        case 'mediumDashDotDot':
            borderStyle = 'dashed';
            borderWidth = '2px';
            break;
        case 'mdeiumDashDot':
            borderStyle = 'dashed';
            borderWidth = '2px';
            break;
        case 'double':
            borderStyle = 'double';
            break;
        case 'thick':
            borderWidth = '3px';
            break;
        default:
            break;
    }
    // console.log(borderStyle, borderWidth);
    return [borderStyle, borderWidth];
}

import { ref } from 'vue';
const data = ref([])
const sheet = ref([])
const themeJson = ref([])
const mergeRanges = ref([])

export default function XLSXPreView() {
    // // 表格数据
    // const [data, setData] = useState([]);
    // // 表格
    // const [sheet, setSheet] = useState([]);
    // // 主题
    // const [themeJson, setThemeJson] = useState([]);
    // // 合并的单元格
    // const [mergeRanges, setMergeRanges] = useState([]);

    registerRenderer('customStylesRenderer', (hotInstance, td, row, column, prop, value, cellProperties) => {
        textRenderer(hotInstance, td, row, column, prop, value, cellProperties);
        // console.log(cellProperties);
        // 填充样式
        if('fill' in cellProperties){
            // 背景颜色
            if('fgColor' in cellProperties.fill && cellProperties.fill.fgColor){
                td.style.background = getColor(cellProperties.fill.fgColor, themeJson.value);
            }
        }
        // 字体样式
        if('font' in cellProperties){
            // 加粗
            if('bold' in cellProperties.font && cellProperties.font.bold){
                td.style.fontWeight = '700';
            }
            // 字体颜色
            if('color' in cellProperties.font && cellProperties.font.color){
                td.style.color = getColor(cellProperties.font.color, themeJson.value);
            }
            // 字体大小
            if('size' in cellProperties.font && cellProperties.font.size){
                td.style.fontSize = cellProperties.font.size + 'px';
            }
            // 字体类型
            if('name' in cellProperties.font && cellProperties.font.name){
                td.style.fontFamily = cellProperties.font.name;
            }
            // 字体倾斜
            if('italic' in cellProperties.font && cellProperties.font.italic){
                td.style.fontStyle = 'italic';
            }
            // 下划线
            if('underline' in cellProperties.font && cellProperties.font.underline){
                // 其实还有双下划线，但是双下划綫css中没有提供直接的设置方式，需要使用额外的css设置，所以我也就先懒得弄了
                td.style.textDecoration = 'underline';
                // 删除线
                if('strike' in cellProperties.font && cellProperties.font.strike){
                    td.style.textDecoration = 'underline line-through';
                }
            }else{
                // 删除线
                if('strike' in cellProperties.font && cellProperties.font.strike){
                    td.style.textDecoration = 'line-through';
                }
            }
            
        }
        // 对齐
        if('alignment' in cellProperties){
            if('horizontal' in cellProperties.alignment){ // 水平
                // 这里我直接用handsontable内置类做了，设置成类似htLeft的样子。
                //（handsontable）其实至支持htLeft, htCenter, htRight, htJustify四种，但是其是它还有centerContinuous、distributed、fill，遇到这几种就会没有效果，也可以自己设置，但是我还是懒的弄了，用到的时候再说吧
                const name =  cellProperties.alignment.horizontal.charAt(0).toUpperCase() + cellProperties.alignment.horizontal.slice(1);
                td.classList.add(`ht${name}`);
            }
            if('vertical' in cellProperties.alignment){ // 垂直
                // 这里我直接用handsontable内置类做了，设置成类似htTop的样子。
                const name =  cellProperties.alignment.vertical.charAt(0).toUpperCase() + cellProperties.alignment.vertical.slice(1);
                td.classList.add(`ht${name}`);
            }
        }
        // 边框
        if('border' in cellProperties){
            if('left' in cellProperties.border &&  cellProperties.border.left){// 左边框
                const [borderWidth, borderStyle] = setBorder(cellProperties.border.left.style);
                let color = '';
                // console.log(row, column, borderWidth, borderStyle);
                if(cellProperties.border.left.color){
                    color = getColor(cellProperties.border.left.color, themeJson.value);
                }
                td.style.borderLeft = `${borderStyle} ${borderWidth} ${color}`;
            }
            if('right' in cellProperties.border &&  cellProperties.border.right){// 左边框
                const [borderWidth, borderStyle] = setBorder(cellProperties.border.right.style);
                // console.log(row, column, borderWidth, borderStyle);
                let color = '';
                if(cellProperties.border.right.color){
                    color = getColor(cellProperties.border.right.color, themeJson.value);
                }
                td.style.borderRight = `${borderStyle} ${borderWidth} ${color}`;
            }
            if('top' in cellProperties.border &&  cellProperties.border.top){// 左边框
                const [borderWidth, borderStyle] = setBorder(cellProperties.border.top.style);
                let color = '';
                // console.log(row, column, borderWidth, borderStyle);
                if(cellProperties.border.top.color){
                    color = getColor(cellProperties.border.top.color, themeJson.value);
                }
                td.style.borderTop = `${borderStyle} ${borderWidth} ${color}`;
            }
            if('bottom' in cellProperties.border &&  cellProperties.border.bottom){// 左边框
                const [borderWidth, borderStyle] = setBorder(cellProperties.border.bottom.style);
                let color = '';
                // console.log(row, column, borderWidth, borderStyle);
                if(cellProperties.border.bottom.color){
                    color = getColor(cellProperties.border.bottom.color, themeJson.value);
                }
                td.style.borderBottom = `${borderStyle} ${borderWidth} ${color}`;
            }
        }
          
    });

    const handleFile = async (e) => {
        const file = e.target.files[0];

        const workbook = new Excel.Workbook();
        await workbook.xlsx.load(file)

        const worksheet = workbook.getWorksheet(1);

        // const sheetRows = worksheet.getRows(1, worksheet.rowCount);
        // setSheet(worksheet)
        sheet.value = worksheet;
        
        // console.log(worksheet.getCell(1, 1).style);
        
        // 遍历工作表中的所有行（包括空行）
        const sheetData = [];
        worksheet.eachRow({ includeEmpty: true }, function(row, rowNumber) {
            // console.log('Row ' + rowNumber + ' = ' + JSON.stringify(row.values));
            // 使用row.values获取每一行的值时总会多出一条空数据(第一条)，这里我把它删除
            const row_values = row.values.slice(1);
            sheetData.push(row_values)
        });
        // setData(sheetData);
        datd.value = sheetData;

        // 将主题xml转换成json
        const themeXml = workbook._themes.theme1;
        const options = {
            ignoreAttributes: false,
            attributeNamePrefix: '_'
        }
        const parser = new XMLParser(options);
        const json = parser.parse(themeXml)
        // setThemeJson(json);
        themeJson.value = json;

        // 获取合并的单元格
        const mergeCells = [];
        
        for(let i in worksheet._merges){
            const {top, left, bottom, right} = worksheet._merges[i].model;
            mergeCells.push({ row: top-1, col: left-1, rowspan: bottom-top+1 , colspan: right-left+1})
        }
        setMergeRanges(mergeCells)
        console.log(worksheet);
    }

    return (
        <>
            <input type="file" onChange={handleFile}/>
            <div id='table_view'>
                <HotTable 
                    data={data.value}
                    readOnly={true}
                    rowHeaders={true}
                    colHeaders={true}
                    width="100vw"
                    height="auto"
                    licenseKey='non-commercial-and-evaluation'
                    rowHeights={function(index) {
                        if(sheet.value.getRow(index+1).height){
                            // exceljs获取的行高不是像素值，事实上，它是23px - 13.8 的一个映射。所以需要将它转化为像素值
                            return sheet.value.getRow(index+1).height * (23 / 13.8);
                        }
                        return 23;// 默认
                    }}
                    colWidths={function(index){
                        if(sheet.value.getColumn(index+1).width){
                            // exceljs获取的列宽不是像素值，事实上，它是81px - 8.22 的一个映射。所以需要将它转化为像素值
                            return sheet.value.getColumn(index+1).width * (81 / 8.22);
                        }
                        return 81;// 默认
                    }}
                    cells={(row, col, prop) => {
                        const cellProperties  = {};
                        const cellStyle = sheet.value.getCell(row+1, col+1).style
                        
                        if(JSON.stringify(cellStyle) !== '{}'){
                            // console.log(row+1, col+1, cellStyle);
                            for(let key in cellStyle){
                                cellProperties[key] = cellStyle[key];
                            }
                        } 
                        return {...cellProperties, renderer: 'customStylesRenderer'};
                    }}
                    mergeCells={mergeRanges}
                />
                
            </div>
        </>
    )
}
</script>